import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Map;

import com.speljohan.rsbot.bot.Bot;
import com.speljohan.rsbot.event.events.ServerMessageEvent;
import com.speljohan.rsbot.event.listeners.PaintListener;
import com.speljohan.rsbot.event.listeners.ServerMessageListener;
import com.speljohan.rsbot.script.Calculations;
import com.speljohan.rsbot.script.Methods;
import com.speljohan.rsbot.script.Script;
import com.speljohan.rsbot.script.wrappers.RSNPC;
import com.speljohan.rsbot.script.wrappers.RSObject;
import com.speljohan.rsbot.script.wrappers.RSTile;

public class VarrockChopper extends Script implements ServerMessageListener,
		PaintListener {

	private final long startTime = System.currentTimeMillis();
	private final int[] bankers_ID = new int[] { 6532, 6533, 6534, 6435 };
	private final RSTile[] path = { new RSTile(3164, 3487),
			new RSTile(3164, 3474), new RSTile(3165, 3461),
			new RSTile(3156, 3458) };
	private final int treeID = 1278, cutTree = 1342, axeID = 1351, wait1 = 200,
			wait2 = 300, bottomY = 3442, leftX = 3141;
	private boolean chopping = false, combat = false;
	private RSTile oldTree = null;
	private int ents, chopped;
	private String doing = "Starting";

	private RSTile checkTile(final RSTile tile) {
		if (tileOnMap(tile)) {
			return tile;
		}
		final RSTile loc = getMyPlayer().getLocation();
		final RSTile walk = new RSTile((loc.getX() + tile.getX()) / 2, (loc
				.getY() + tile.getY()) / 2);
		return walk;
	}

	private void chop() {
		doing = "Chopping Trees";
		if (!chopping) {
			chopping = !chopping;
		}
		final RSObject tree = findObjectCustom(treeID);
		if (tree == null) {
			return;
		}
		if (tree.getLocation().getY() < bottomY
				|| getMyPlayer().getLocation().getX() < leftX) {
			doing = "Going back to Trees";
			chopping = false;
			return;
		}
		if (!tileOnScreen(tree.getLocation())) {
			walkTileMM(randomTile(tree.getLocation(), 1));
			return;
		}
		cutTree(tree.getLocation());
		oldTree = tree.getLocation();
	}

	private void cutTree(final RSTile tree) {
		RSTile corner = null;
		corner = new RSTile(tree.getX() - 1, tree.getY() + 1);
		if (getObjectAt(corner) == null
				|| getObjectAt(corner).getID() != treeID) {
			corner = new RSTile(tree.getX() + 1, tree.getY() + 1);
			if (getObjectAt(corner) == null
					|| getObjectAt(corner).getID() != treeID) {
				corner = new RSTile(tree.getX() - 1, tree.getY() - 1);
				if (getObjectAt(corner) == null
						|| getObjectAt(corner).getID() != treeID) {
					corner = new RSTile(tree.getX() + 1, tree.getY() - 1);
					if (getObjectAt(corner) == null
							|| getObjectAt(corner).getID() != treeID) {
						log("Tree Finding Error - Trying Again");
						setCameraRotation(getCameraAngle() + random(-30, 30));
					}
				}
			}
		}
		final Point tre = Calculations.tileToScreen(tree);
		final Point cor = Calculations.tileToScreen(corner);
		if (tre.x < 0 || tre.y < 0 || cor.x < 0 || cor.y < 0) {
			return;
		}
		final Point click = new Point((tre.x + cor.x) / 2 + random(-2, 2),
				(tre.y + cor.y) / 2 + random(-2, 2));
		clickMouse(click, true);
	}

	private RSObject findObjectCustom(final int id) {
		// Changed to find the nearest, reachable!
		// fixed, lol, getObjectAt want a real xy not this one
		RSObject cur = null;
		int dist = Integer.MAX_VALUE;
		final RSTile start = getMyPlayer().getLocation();
		for (int x = -10; x < 11; x++) {
			for (int y = 10; y > -11; y--) {
				final RSObject temp = getObjectAt(start.getX() + x, start
						.getY()
						+ y);
				if (temp != null) {
					if (temp.getID() == id) {
						if (distanceTo(temp) < dist) {
							dist = distanceTo(temp);
							cur = temp;
						}
					}
				}
			}
		}
		return cur;
	}

	@Override
	public String getAuthor() {
		return "Fusion89k";
	}

	@Override
	public String getName() {
		return "Varrock Chopper";
	}

	@Override
	public String getScriptCategory() {
		return "Woodcutting";
	}

	@Override
	public String getScriptDescription() {
		return "<html>\n" + "<head></head>\n"
				+ "<body bgcolor=\"black\" text=\"white\">\n" + "<center>"
				+ "<h2>" + getName() + "</h2>" + "</center>\n"
				+ "<b>Author:</b> " + getAuthor() + "<br />"
				+ "<b>Version:</b> " + getVersion()
				+ "<BR>Have axe in inventory or equipped" + "</body>\n"
				+ "</html>";
	}

	@Override
	public double getVersion() {
		return 1;
	}

	private boolean isMoving() {
		if (!getMyPlayer().isMoving()) {
			return false;
		}
		if (chopping) {
			return true;
		}
		if (distanceTo(getDestination()) < 7 && getDestination() != null
				&& Methods.distanceBetween(path[0], getDestination()) > 5) {
			return false;
		}
		return true;
	}

	private RSTile locate() {
		RSTile min = path[0];
		for (int i = 1; i < path.length; i++) {
			if (distanceTo(path[i]) < distanceTo(min)) {
				if (getDestination() != null) {
					if (Methods.distanceBetween(path[i], getDestination()) < 4) {
						min = path[i];
						continue;
					}
				}
				min = path[i];
			}
		}
		return min;
	}

	@Override
	public int loop() {
		setCameraAltitude(true);
		if (isLoggedIn() && !isCarryingItem(axeID)) {
			log("Axe Broken - Logging Out");
			stopAllScripts();
		}
		if (getMyPlayer().isInCombat() && !combat
				|| !getMyPlayer().isInCombat() && combat) {
			combat = !combat;
		}
		if (isMoving() && !combat) {
			return random(wait1, wait2);
		}
		if (combat) {
			doing = "In Combat";
			setRun(true);
			walk(true);
			return random(wait1, wait2);
		}
		if (isInventoryFull()) {
			if (chopping) {
				chopping = !chopping;
			}
			if (distanceTo(path[0]) > 4) {
				doing = "Walking to Bank";
				walk(true);
			} else {
				if (!bank.getInterface().isValid()) {
					doing = "Finding Banker";
					final RSNPC banker = getNearestFreeNPCByID(bankers_ID);
					if (banker != null) {
						if (!tileOnScreen(banker.getLocation())) {
							walkTileMM(banker.getLocation());
						} else {
							doing = "Banking";
							final Point click = Calculations
									.tileToScreen(banker.getLocation());
							clickMouse(click.x + random(-2, 2), click.y
									+ random(-2, 2), false);
							atMenu("Bank Banker");
						}
					}
				} else {
					doing = "Depositing";
					bank.depositAllExcept(axeID);
				}
			}
		} else {
			if (!chopping && distanceTo(path[path.length - 1]) > 4) {
				doing = "Walking to Trees";
				walk(false);
			} else {
				if (chopping && getMyPlayer().getAnimation() != -1
						&& !getMyPlayer().isMoving()) {
					final RSObject tree = getObjectAt(oldTree);
					if (tree != null) {
						if (tree.getID() != treeID && tree.getID() != cutTree) {
							log("Possible Ent");
							doing = "Avoiding Ent";
							ents++;
							log("Ent ID: " + tree.getID());
							walkTileMM(randomTile(getMyPlayer().getLocation(),
									1));
						} else if (tree.getID() == cutTree) {
							chop();
						}
					} else {
						log("Ent Detection Error - Empty Tree");
					}
				} else {
					chop();
				}
			}
		}
		return random(wait1, wait2);
	}

	@Override
	public void onFinish() {
		Bot.getEventManager().removeListener(PaintListener.class, this);
	}

	public void onRepaint(final Graphics g) {
		if (isLoggedIn()) {
			long millis = System.currentTimeMillis() - startTime;
			final long hours = millis / (1000 * 60 * 60);
			millis -= hours * 1000 * 60 * 60;
			final long minutes = millis / (1000 * 60);
			millis -= minutes * 1000 * 60;
			final long seconds = millis / 1000;
			final int topX = 515 - 173, topY = 337 - 80, x = topX + 5;
			int y = topY + 5;
			g.setColor(new Color(0, 100, 0, 100));
			g.fill3DRect(topX, topY, 515 - topX, 337 - topY, true);
			g.setColor(Color.green);
			g.drawString("Runtime: " + hours + "h " + minutes + "min "
					+ seconds + "sec.", x, y += 15);
			g.drawString("Trees Chopped: " + Integer.toString(chopped), x,
					y += 15);
			g.drawString("Ents: " + ents, x, y += 15);
			g.drawString("Status: " + doing, x, y += 15);
		}
	}

	@Override
	public boolean onStart(final Map<String, String> args) {
		return true;
	}

	private RSTile randomTile(final RSTile location) {
		return randomTile(location, 2);
	}

	private RSTile randomTile(final RSTile location, final int rand) {
		final int x = location.getX(), y = location.getY();
		return new RSTile(random(x - rand, x + rand),
				random(y - rand, y + rand));
	}

	public void serverMessageRecieved(final ServerMessageEvent e) {
		final String word = e.getMessage().toLowerCase();
		if (word.contains("logs")) {
			chopped++;
		}
	}

	private void walk(final boolean toBank) {
		setCompass('n');
		if (getEnergy() >= random(60, 100)) {
			setRun(true);
		}
		final RSTile start = locate();
		int loc = 0;
		for (int i = 0; i < path.length; i++) {
			if (start.equals(path[i])) {
				loc = i;
				break;
			}
		}
		RSTile walk = null;
		if (toBank) {
			if (loc == 0) {
				walk = randomTile(path[0]);
			} else {
				walk = randomTile(path[loc - 1]);
			}
		} else {
			if (loc == path.length - 1) {
				walk = randomTile(path[path.length - 1]);
			} else {
				walk = randomTile(path[loc + 1]);
			}
		}
		walk = checkTile(walk);
		walkTileMM(walk);
	}

}
